package com.fancy.cc.security.component;

import com.alibaba.fastjson.JSONObject;
import com.fancy.cc.common.exception.ApiException;
import com.fancy.cc.common.exception.NotLoginException;
import com.fancy.cc.mapper.UmsAdminMapper;
import com.fancy.cc.mapper.UmsAdminRoleRelationMapper;
import com.fancy.cc.mapper.UmsMemberMapper;
import com.fancy.cc.model.UmsAdmin;
import com.fancy.cc.model.UmsAdminRoleRelation;
import com.fancy.cc.model.UmsMember;
import com.fancy.cc.model.UmsResource;
import com.fancy.cc.model.dto.UmsUserDTO;
import com.fancy.cc.security.domain.AdminUserDetails;
import com.fancy.cc.security.util.CurrentUserUtil;
import com.fancy.cc.security.util.JwtTokenUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * JWT登录授权过滤器
 * Created by macro on 2018/4/26.
 */
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Autowired
    private UmsAdminMapper adminMapper;

    @Resource
    private UmsMemberMapper memberMapper;

    @Resource
    private UmsAdminRoleRelationMapper umsAdminRoleRelationMapper;

    public AdminUserDetails loadUserByUserId(String uid) throws UsernameNotFoundException {
        UmsAdmin umsAdmin = adminMapper.selectByPrimaryKey(Long.parseLong(uid));
        if (Objects.isNull(umsAdmin)) {
            throw new NotLoginException();
        }
        UmsUserDTO umsUserDTO = UmsUserDTO.from(umsAdmin);
        UmsAdminRoleRelation byAdminId = umsAdminRoleRelationMapper.getByAdminId(Long.valueOf(uid));
        if (Objects.nonNull(byAdminId)) {
            umsUserDTO.setRole(Math.toIntExact(byAdminId.getRoleId()));
        }
        List<UmsResource> list = umsAdminRoleRelationMapper.getResourceList(umsUserDTO.getId());
        return new AdminUserDetails(umsUserDTO, list);
    }

    public AdminUserDetails loadUserByMemberId(String uid, String merchantId) {
        UmsMember member = memberMapper.selectByPrimaryKey(Long.parseLong(uid));
        if (Objects.isNull(member)) {
            throw new NotLoginException();
        }
        UmsUserDTO umsUserDTO = UmsUserDTO.from(member, merchantId);
        return new AdminUserDetails(umsUserDTO, new ArrayList<>());
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {

        String authHeader = request.getHeader(this.tokenHeader);
        if (authHeader != null && authHeader.startsWith(this.tokenHead)) {
            String authToken = authHeader.substring(this.tokenHead.length());// The part after "Bearer "
            String userType = request.getHeader("user-type");
            String merchantId = request.getHeader("merchant");
            String uid = jwtTokenUtil.getUserIdFromToken(authToken);
            LOGGER.info("doFilterInternal_checking_token:{} userType:{} merchantId:{} uid:{}", authToken, userType, merchantId, uid);
            if (uid != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                AdminUserDetails securityUser;
                if (StringUtils.isBlank(userType)) {
                    securityUser = loadUserByUserId(uid);
                } else if ("member".equals(userType)) {
                    securityUser = loadUserByMemberId(uid, merchantId);
                } else {
                    throw new ApiException("请求头参数异常");
                }
                if (jwtTokenUtil.validateToken(authToken, securityUser.getId().toString())) {
                    Collection<? extends GrantedAuthority> authorities = null;
                    if (StringUtils.isBlank(userType)) {
                        authorities = securityUser.getAuthorities();
                    }
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(securityUser, null, authorities);
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    LOGGER.info("authenticated_securityUser:{}", JSONObject.toJSONString(securityUser));
                    SecurityContextHolder.getContext().setAuthentication(authentication);

                    CurrentUserUtil.addCurrentUser(securityUser);
                }
            }
        } else {
            //String userType = request.getHeader("user-type");
            //String merchantId = request.getHeader("merchant");
            //LOGGER.info("doFilterInternal_checking_userType:{} merchantId:{} authHeader:{}",userType,merchantId,authHeader);
            //LOGGER.info("doFilterInternal_checking_currentUse:{}",
             //       JSONObject.toJSONString(CurrentUserUtil.getCurrentUser()));
            if (Objects.nonNull(CurrentUserUtil.getCurrentUser())) {
                //LOGGER.info("doFilterInternal_currentUser12121:{}",JSONObject.toJSONString(CurrentUserUtil.getCurrentUser()));
                CurrentUserUtil.remove();
            }
        }
        chain.doFilter(request, response);
    }


}
